/**
 * Copyright (C) 2008+ Spark Zheng
 *
 * @file	src/threadpool.h
 * @brief 
 *		A simple compact threadpool. A generate infrastructure.
 *		-1. tpool init/exit
 *		-2. tpool wait
 *
 * @module      dlib
 * @see		dlib
 *
 * @history
 *		version 0.0.1 initialized by Spark Zheng, implement generate functions
 *		version 0.1.0 modified by Spark Zheng, add gentle wait: dlib_tpool_wait
 *		version 0.2.0 modified by Spark Zheng, tidy it up as generate-utils module
 *		version 0.2.1 modified by Spark Zheng, add detach attribution for each worker
 */

#ifndef _DLIB_THREADSPOOL_H
#define _DLIB_THREADSPOOL_H

#ifdef __cplusplus
extern "C" {
#endif
	
#include <pthread.h>
#include <stdio.h>
#include "global.h"

/** task special function model */
typedef void *(*dlib_thread_fn)(void *arg);

typedef void *(*dlib_task_fn)(void *thread_data, void *task_arg);
typedef void *(*dlib_totask_fn)(void *res_data, void *totask_arg);
typedef void *(*dlib_detask_fn)(void *res_data, void *detask_arg);

/** thread special function[init/exit] model */
typedef void *(*dlib_tinit_fn)(void *arg);
typedef void (*dlib_texit_fn)(void *arg);

typedef struct tpool dlib_tpool_t;

#ifdef _DEBUG
typedef struct tstatics dlib_tstatics_t;
#endif
typedef struct dtask dlib_task_t;
typedef struct titem dlib_titem_t;

/**
 * dlib_tpool_init
 * @brief threadpool construct. SYNC
 * @param init_num: tpool initial worker number
 * @param max_num: tpool maximum worker number
 * @param tinit_cb: thread init callback function, could be NULL
 * @param tinit_arg: thread init callback argument, could be NULL
 * @param texit_cb: thread exit callback function, could be NULL
 */
extern dlib_tpool_t *dlib_tpool_init(uint32_t init_num, uint32_t max_num,
				     dlib_tinit_fn tinit_cb, void *tinit_arg,
				     dlib_texit_fn texit_cb);

/**
 * dlib_tpool_settask
 * @brief threadpool set default task-execute parameters. SYNC
 * @param tp: tpool
 * @param task_cb: default task-execute callback function
 * @param task_arg: default callback function argument 
 */
extern int dlib_tpool_settask(dlib_tpool_t *tp, dlib_task_fn task_cb,
			      void *task_arg);

/**
 * dlib_tpool_settotask
 * @brief threadpool set default timeout parameters. SYNC
 * @param tp: tpool
 * @param timeout: default timeout number
 * @param totask_cb: default timeout callback function
 * @param totask_arg: default callback function argument 
 */
extern int dlib_tpool_settotask(dlib_tpool_t *tp, uint32_t timeout,
				dlib_totask_fn totask_cb, void *totask_arg);

/**
 * dlib_tpool_setdetask
 * @brief threadpool set default task-destructure-callback parameters. SYNC
 * @param tp: tpool
 * @param detask_cb: default task-destructure callback function
 * @param detask_arg: default callback function argument 
 */
extern int dlib_tpool_setdetask(dlib_tpool_t *tp, dlib_detask_fn detask_cb,
				void *detask_arg);

/**
 * dlib_tpool_execute
 * @brief threadpool schedule a worker. SYNC
 * @param tp: tpool
 * @param tnice: task nice value, min value is higher priority
 * @param task_cb: task function, could be NULL
 *		-If NULL, then will use def_task_cb
 *		-Caution, def_task_cb & task_cb couldn't all be NULL
 * @param task_arg: task function argument, could be NULL
 */
extern int dlib_tpool_execute(dlib_tpool_t *tp, uint32_t tnice,
			      dlib_task_fn task_cb, void *task_arg);

/**
 * dlib_tpool_execute9
 * @brief threadpool schedule a worker by 9 parameters. SYNC
 * @param tp: tpool
 * @param tnice: task nice value, min value is higher priority
 * @param task_cb: task function
 * @param task_arg: task function argument
 * @param timeo: task timeout number
 * @param totask_cb: task timeout call back function
 * @param totask_arg: task timeout argument
 * @param detask_cb: task finished call back function
 * @param detask_arg: task finished argument
 */
extern int dlib_tpool_execute9(dlib_tpool_t *tp, uint32_t tnice,
			       dlib_task_fn task_cb, void *task_arg,
			       uint32_t timeo, dlib_totask_fn totask_cb,
			       void *totask_arg, dlib_detask_fn detask_cb,
			       void *detask_arg);

/**
 * dlib_tpool_timeout
 * @brief threadpool handle timeout queue. SYNC
 *	-Caution, it will block the invoker 
 *	-Like dlib_tpool_retrieve
 * @param tp: tpool
 */
extern void *dlib_tpool_timeout(dlib_tpool_t *tp);

/**
 * dlib_tpool_timeout_async
 * @brief threadpool handle timeout queue. ASYNC
 *	-create a thread to listen for timeout asynchronously
 *	-Like dlib_tpool_retrieve_async
 * @param tp: tpool
 */
extern int dlib_tpool_timeout_async(dlib_tpool_t *tp);

/**
 * dlib_tpool_retrieve
 * @brief threadpool retrieve results. SYNC
 *	-Caution, it will block the invoker 
 *	-Result Queue operation, also can be not care about result
 * @param tp: tpool
 */
extern void *dlib_tpool_retrieve(dlib_tpool_t *tp);

/**
 * dlib_tpool_retrieve_async
 * @brief threadpool retrieve results. ASYNC
 *	-create a thread to listen for result arrived asynchronously
 *	-Result Queue operation, also can be not care about result
 * @param tp: tpool
 */
extern int dlib_tpool_retrieve_async(dlib_tpool_t *tp);

/**
 * dlib_tpool_wait
 * @brief Threadpool wait for all thread stop gently. SYNC or ASYNC
 *	-Caution, Don't use it followed by dlib_tpool_timeout and
 *		dlib_tpool_retrieve, otherwise, you need dlib_tpoo_timeout_async
 *		and dlib_tpool_retrieve_async
 *	-Cause all be done
 * @param tp, tpool
 */
extern void *dlib_tpool_wait(dlib_tpool_t *tp);

/**
 * dlib_tpool_exit
 * @brief threadpool destruct, will force all thread quit. SYNC
 * @param tp, tpool
 */
extern void dlib_tpool_exit(dlib_tpool_t *tp);

/**
 * dlib_tpool_dump
 * @brief threadpool runtime dump. SYNC
 * @param tp, tpool
 * @param fd, out fd, NULL means stdout
 */
extern void dlib_tpool_dump(dlib_tpool_t *tp, FILE *fd);


/** threads cluster implement */
typedef struct dlib_thread dlib_thread_t; 

typedef enum {
	thread_init = 0,
	thread_running,
	thread_fini
} dlib_thread_stat_t;

struct dlib_thread {
	dlib_thread_fn		tcb;
	void			*thread_arg;
	pthread_t		tid;
	dlib_thread_stat_t	status;
	pthread_mutex_t		lock;
};

/**
 * dlib_threads_init
 * @brief create a threads cluster
 * @param num, number of thread in cluster
 * @param task_fn, working function
 * @param arg, working argument
 */
extern dlib_thread_t *dlib_threads_init(size_t num, dlib_thread_fn task_cb, void *arg);

/**
 * dlib_thread_new
 * @brief put a thread into working
 * @param thread, thread struct
 * @param task_fn, working function
 * @param arg, working argument
 */
extern int dlib_thread_new(dlib_thread_t *thread, dlib_thread_fn task_cb, void *arg);

/**
 * dlib_thread_del
 * @brief get a thread outof working
 * @param thread, thread structure
 */
extern int dlib_thread_del(dlib_thread_t *thread);

/**
 * dlib_threads_exit
 * @brief destroy a threads cluster
 * @param threads, thread cluster
 * @param num, number of thread in cluster
 */
extern void dlib_threads_exit(dlib_thread_t *threads, size_t num);

#ifdef __cplusplus
}
#endif
#endif
